"""
python3 函数
"""

'''
函数代码块以 def 关键词开头，后接函数标识符名称和圆括号 ()
任何传入参数和自变量必须放在圆括号中间，圆括号之间可以用于定义参数
函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明
函数内容以冒号起始，并且缩进
return [表达式] 结束函数，选择性地返回一个值给调用方。不带表达式的return相当于返回 None
'''

def hello():
    print("Hello World!")
hello()

def area(width, height):
    return width * height
w = 4
h = 5
print("width =", w, " height =", h, " area =", area(w, h))

'''
参数
    必需参数
    关键字参数
    默认参数
    不定长参数
'''
# 使用关键字参数允许函数调用时参数的顺序与声明时不一致，因为 Python 解释器能够用参数名匹配参数值
def printme(str):
    print(str)
printme(str="菜鸟教程")

# 调用函数时，如果没有传递参数，则会使用默认参数
def printinfo(name, age=35):
    print("名字: ", name)
    print("年龄: ", age)
printinfo(age=50, name="runoob")
printinfo(name="runoob")

# 加了星号（*）的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数，它就是一个空元组
def printinfo(arg1, *vartuple):
    print("输出: ")
    print(arg1)
    for var in vartuple:
        print(var)
printinfo(10)
printinfo(70, 60, 50)

'''
匿名函数
lambda 只是一个表达式，函数体比 def 简单很多
lambda的主体是一个表达式，而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去
lambda 函数拥有自己的命名空间，且不能访问自己参数列表之外或全局命名空间里的参数
虽然lambda函数看起来只能写一行，却不等同于C或C++的内联函数，后者的目的是调用小函数时不占用栈内存从而增加运行效率
'''
sum = lambda arg1, arg2: arg1 + arg2
print("相加后的值为 : ", sum(10, 20))

'''
变量作用域
    L （Local） 局部作用域
    E （Enclosing） 闭包函数外的函数中
    G （Global） 全局作用域
    B （Built-in） 内建作用域
以 L –> E –> G –>B 的规则查找\
即：在局部找不到，便会去局部外的局部找（例如闭包），再找不到就会去全局找，再者去内建中找
Python 中只有模块（module），类（class）以及函数（def、lambda）才会引入新的作用域，
其它的代码块（如 if/elif/else/、try/except、for/while等）是不会引入新的作用域的，
也就是说这些语句内定义的变量，外部也可以访问
'''
x = int(2.9)  # 内建作用域
g_count = 0   # 全局作用域
def outer():
    o_count = 1  # 闭包函数外的函数中
    def inner():
        i_count = 2  # 局部作用域


# 非模块、类、函数中的代码块，外部可以访问内部定义的变量
if True:
    msg = 'I am from Runoob'
print(msg)

# 全局变量与局部变量
total = 0 # 这是一个全局变量
def sum( arg1, arg2 ):
    total = arg1 + arg2 # total在这里是局部变量.
    print ("函数内是局部变量 : ", total)
    return total
sum(10, 20)
print("函数外是全局变量 : ", total)

'''
global 和 nonlocal 关键字
当内部作用域想修改外部作用域的变量时，就要用到global和nonlocal关键字了
'''
# global 修改全局变量
num = 1
def fun1():
    global num  # 需要使用 global 关键字声明
    print(num)
    num = 123
    print(num)
fun1()

# nonlocal 修改嵌套作用域（enclosing 作用域，外层非全局作用域）中的变量
def outer():
    num = 10
    def inner():
        nonlocal num   # nonlocal关键字声明
        num = 100
        print(num)
    inner()
    print(num)
outer()

'''
错误信息为局部作用域引用错误，因为 test 函数中的 a 使用的是局部，未定义，无法修改。
a = 10
def test():
    a = a + 1
    print(a)
test()
'''
